/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {ArkFile, AstTreeUtils, ts} from "arkanalyzer";
import Logger, {LOG_MODULE_TYPE} from 'arkanalyzer/lib/utils/logger';
import {BaseChecker, BaseMetaData, FileMatcher, MatcherCallback, MatcherTypes, Utils} from '../../Index';
import {Defects} from "../../model/Defects";
import {Rule} from "../../model/Rule";
import {RuleListUtil} from "../../utils/common/DefectsList";
import {IssueReport} from '../../model/Defects';
import {RuleFix} from "../../model/Fix";

const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'AwaitThenableCheck');
const gMetaData: BaseMetaData = {
    severity: 2,
    ruleDocPath: "docs/member-delimiter-style-check.md",
    description: "Require a specific member delimiter style for interfaces and type literals",
};
type MultiLineOption = 'comma' | 'none' | 'semi';
type SingleLineOption = 'comma' | 'semi';
type DelimiterConfig = {
    multiline?: {
        delimiter?: MultiLineOption;
        requireLast?: boolean;
    };
    singleline?: {
        delimiter?: SingleLineOption;
        requireLast?: boolean;
    };
};
type Options = [
    {
        multiline?: {
            delimiter?: MultiLineOption;
            requireLast?: boolean;
        };
        multilineDetection?: 'brackets' | 'last-member';
        overrides?: {
            interface?: DelimiterConfig;
            typeLiteral?: DelimiterConfig;
        };
        singleline?: {
            delimiter?: SingleLineOption;
            requireLast?: boolean;
        };
    },
];

export class MemberDelimiterStyleCheck implements BaseChecker {
    readonly metaData: BaseMetaData = gMetaData;
    public rule: Rule;
    public defects: Defects[] = [];
    public issues: IssueReport[] = [];
    private issueMap: Map<string, IssueReport> = new Map();
    private multilineDetection: 'brackets' | 'last-member' = 'brackets';
    private interfaceMultilineDelimiter: MultiLineOption = 'semi';
    private interfaceMultilineRequireLast: boolean = true;
    private interfaceSingleLineDelimiter: SingleLineOption = 'semi';
    private interfaceSingleLineRequireLast: boolean = false;
    private typeLiteralMultilineDelimiter: MultiLineOption = 'semi';
    private typeLiteralMultilineRequireLast: boolean = true;
    private typeLiteralSingleLineDelimiter: SingleLineOption = 'semi';
    private typeLiteralSingleLineRequireLast: boolean = false;

    private fileMatcher: FileMatcher = {
        matcherType: MatcherTypes.FILE,
    };

    public registerMatchers(): MatcherCallback[] {
        const fileMatcherCb: MatcherCallback = {
            matcher: this.fileMatcher,
            callback: this.check
        };
        return [fileMatcherCb];
    }

    public check = (arkFile: ArkFile) => {
        if (this.rule && this.rule.option) {
            const option = this.rule.option as Options;
            if (option.length > 0) {
                this.multilineDetection = option[0]?.multilineDetection || 'brackets';
                this.interfaceMultilineDelimiter = option[0]?.multiline?.delimiter || 'semi';
                this.interfaceMultilineRequireLast = option[0]?.multiline?.requireLast || true;
                this.interfaceSingleLineDelimiter = option[0]?.singleline?.delimiter || 'semi';
                this.interfaceSingleLineRequireLast = option[0]?.singleline?.requireLast || false;
                this.typeLiteralMultilineDelimiter = option[0]?.multiline?.delimiter || 'semi';
                this.typeLiteralMultilineRequireLast = option[0]?.multiline?.requireLast || true;
                this.typeLiteralSingleLineDelimiter = option[0]?.singleline?.delimiter || 'semi';
                this.typeLiteralSingleLineRequireLast = option[0]?.singleline?.requireLast || false;
                if (option[0]?.overrides) {
                    this.interfaceMultilineDelimiter = option[0]?.overrides?.interface?.multiline?.delimiter || 'semi';
                    this.interfaceMultilineRequireLast = option[0]?.overrides?.interface?.multiline?.requireLast || true;
                    this.interfaceSingleLineDelimiter = option[0]?.overrides?.interface?.singleline?.delimiter || 'semi';
                    this.interfaceSingleLineRequireLast = option[0]?.overrides?.interface?.singleline?.requireLast || false;
                    this.typeLiteralMultilineDelimiter = option[0]?.overrides?.typeLiteral?.multiline?.delimiter || 'semi';
                    this.typeLiteralMultilineRequireLast = option[0]?.overrides?.typeLiteral?.multiline?.requireLast || true;
                    this.typeLiteralSingleLineDelimiter = option[0]?.overrides?.typeLiteral?.singleline?.delimiter || 'semi';
                    this.typeLiteralSingleLineRequireLast = option[0]?.overrides?.typeLiteral?.singleline?.requireLast || false;
                }
            }
        }
        const code = arkFile.getCode();
        if (!code) {
            return;
        }
        const asRoot = AstTreeUtils.getASTNode(arkFile.getName(), code);
        const sourceFileObject = ts.getParseTreeNode(asRoot);
        if (sourceFileObject == undefined) {
            return;
        }
        this.loopNode(arkFile, asRoot, sourceFileObject);
        this.reportSortedIssues()
    }

    public loopNode(targetFile: ArkFile, sourceFile: ts.SourceFile, aNode: ts.Node) {
        const children = aNode.getChildren();
        for (const child of children) {
            if (ts.isInterfaceDeclaration(child)) {
                this.checkInterfaceMembers(child, sourceFile, targetFile);
            } else if (ts.isTypeAliasDeclaration(child)) {
                this.checkTypeAliasMembers(child, sourceFile, targetFile);
            }
            this.loopNode(targetFile, sourceFile, child);
        }
    }

    private checkInterfaceMembers(child: ts.InterfaceDeclaration, sourceFile: ts.SourceFile, arkFile: ArkFile): void {
        const members = child?.members;
        if (!members) {
            return;
        }
        for (let i = 0; i < members.length; i++) {
            const member = members[i];
            const isLastMember = i === members.length - 1;
            let startLine = this.getStartLine(child, sourceFile);
            if (this.multilineDetection === 'last-member') {
                startLine = this.getStartLine(members[members.length - 1], sourceFile);
            }
            let endLine = this.getEndLine(child, sourceFile);
            let isSameLine = startLine === endLine;
            if (member.getChildren().length > 1) {
                let lastToken = member.getChildren()[member.getChildren().length - 1];
                let positionInfo = this.getPositionInfo(member, sourceFile);
                if (isSameLine && isLastMember) {
                    if (this.interfaceSingleLineRequireLast) {
                        if (this.interfaceSingleLineDelimiter === 'semi' && lastToken.kind !== ts.SyntaxKind.SemicolonToken) {
                            let result = this.commaMemberText(lastToken, member);
                            let fix: RuleFix | undefined;
                            fix = {range: [member.getStart(), member.getEnd()], text: result};
                            const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                            this.issueMap.set(defect.fixKey, {defect, fix});
                        }
                        if (this.interfaceSingleLineDelimiter === 'comma' && lastToken.kind !== ts.SyntaxKind.CommaToken) {
                            let result = this.semicolonMemberText(lastToken, member);
                            let fix: RuleFix | undefined;
                            fix = {range: [member.getStart(), member.getEnd()], text: result};
                            const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                            this.issueMap.set(defect.fixKey, {defect, fix});
                        }
                    } else {
                        if (lastToken.kind === ts.SyntaxKind.CommaToken || lastToken.kind === ts.SyntaxKind.SemicolonToken) {
                            let result = member.getText().slice(0, -1);
                            let fix: RuleFix | undefined;
                            fix = {range: [member.getStart(), member.getEnd()], text: result};
                            const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                            this.issueMap.set(defect.fixKey, {defect, fix});
                        }
                    }
                } else if (isSameLine) {
                    if (this.interfaceSingleLineDelimiter === 'semi' && lastToken.kind !== ts.SyntaxKind.SemicolonToken) {
                        let result = this.commaMemberText(lastToken, member);
                        let fix: RuleFix | undefined;
                        fix = {range: [member.getStart(), member.getEnd()], text: result};
                        const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                        this.issueMap.set(defect.fixKey, {defect, fix});
                    }
                    if (this.interfaceSingleLineDelimiter === 'comma' && lastToken.kind !== ts.SyntaxKind.CommaToken) {
                        let result = this.semicolonMemberText(lastToken, member);
                        let fix: RuleFix | undefined;
                        fix = {range: [member.getStart(), member.getEnd()], text: result};
                        const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                        this.issueMap.set(defect.fixKey, {defect, fix});
                    }
                } else if (!isSameLine && isLastMember) {
                    if (this.interfaceMultilineRequireLast) {
                        if (this.interfaceMultilineDelimiter === 'none' && (lastToken.kind === ts.SyntaxKind.CommaToken || lastToken.kind === ts.SyntaxKind.SemicolonToken)) {
                            let result = member.getText().slice(0, -1);
                            let fix: RuleFix | undefined;
                            fix = {range: [member.getStart(), member.getEnd()], text: result};
                            const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                            this.issueMap.set(defect.fixKey, {defect, fix});
                        }
                        if (this.interfaceMultilineDelimiter === 'semi' && lastToken.kind !== ts.SyntaxKind.SemicolonToken) {
                            let result = this.commaMemberText(lastToken, member);
                            let fix: RuleFix | undefined;
                            fix = {range: [member.getStart(), member.getEnd()], text: result};
                            const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                            this.issueMap.set(defect.fixKey, {defect, fix});
                        }
                        if (this.interfaceMultilineDelimiter === 'comma' && lastToken.kind !== ts.SyntaxKind.CommaToken) {
                            let result = this.semicolonMemberText(lastToken, member);
                            let fix: RuleFix | undefined;
                            fix = {range: [member.getStart(), member.getEnd()], text: result};
                            const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                            this.issueMap.set(defect.fixKey, {defect, fix});
                        }
                    } else {
                        if (this.interfaceMultilineDelimiter === 'none' && (lastToken.kind === ts.SyntaxKind.CommaToken || lastToken.kind === ts.SyntaxKind.SemicolonToken)) {
                            let result = member.getText().slice(0, -1);
                            let fix: RuleFix | undefined;
                            fix = {range: [member.getStart(), member.getEnd()], text: result};
                            const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                            this.issueMap.set(defect.fixKey, {defect, fix});
                        }
                    }
                } else {
                    if (this.interfaceMultilineDelimiter === 'none' && (lastToken.kind === ts.SyntaxKind.CommaToken || lastToken.kind === ts.SyntaxKind.SemicolonToken)) {
                        let result = member.getText().slice(0, -1);
                        let fix: RuleFix | undefined;
                        fix = {range: [member.getStart(), member.getEnd()], text: result};
                        const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                        this.issueMap.set(defect.fixKey, {defect, fix});
                    }
                    if (this.interfaceMultilineDelimiter === 'semi' && lastToken.kind !== ts.SyntaxKind.SemicolonToken) {
                        let result = this.commaMemberText(lastToken, member);
                        let fix: RuleFix | undefined;
                        fix = {range: [member.getStart(), member.getEnd()], text: result};
                        const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                        this.issueMap.set(defect.fixKey, {defect, fix});
                    }
                    if (this.interfaceMultilineDelimiter === 'comma' && lastToken.kind !== ts.SyntaxKind.CommaToken) {
                        let result = this.semicolonMemberText(lastToken, member);
                        let fix: RuleFix | undefined;
                        fix = {range: [member.getStart(), member.getEnd()], text: result};
                        const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                        this.issueMap.set(defect.fixKey, {defect, fix});
                    }
                }
            }
        }
    }

    private checkTypeAliasMembers(child: ts.TypeAliasDeclaration | ts.TypeElement, sourceFile: ts.SourceFile, arkFile: ArkFile): void {
        if (ts.isTypeAliasDeclaration(child) || ts.isPropertySignature(child)) {
            if (ts.isTypeLiteralNode(child.type!)) {
                let members = child.type.members;
                for (let i = 0; i < members.length; i++) {
                    const member = members[i];
                    const isLastMember = i === members.length - 1;
                    let startLine = this.getStartLine(child.type, sourceFile);
                    if (this.multilineDetection === 'last-member') {
                        startLine = this.getStartLine(members[members.length - 1], sourceFile);
                    }
                    let endLine = this.getEndLine(child.type, sourceFile);
                    let isSameLine = startLine === endLine;
                    if (member.getChildren().length > 1) {
                        let lastToken = member.getChildren()[member.getChildren().length - 1];
                        let positionInfo = this.getPositionInfo(member, sourceFile);
                        if (isSameLine && isLastMember) {
                            if (this.typeLiteralSingleLineRequireLast) {
                                if (this.typeLiteralSingleLineDelimiter === 'semi' && lastToken.kind !== ts.SyntaxKind.SemicolonToken) {
                                    let result = this.commaMemberText(lastToken, member);
                                    let fix: RuleFix | undefined;
                                    fix = {range: [member.getStart(), member.getEnd()], text: result};
                                    const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                                    this.issueMap.set(defect.fixKey, {defect, fix});
                                }
                                if (this.typeLiteralSingleLineDelimiter === 'comma' && lastToken.kind !== ts.SyntaxKind.CommaToken) {
                                    let result = this.semicolonMemberText(lastToken, member);
                                    let fix: RuleFix | undefined;
                                    fix = {range: [member.getStart(), member.getEnd()], text: result};
                                    const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                                    this.issueMap.set(defect.fixKey, {defect, fix});
                                }
                            } else {
                                if (lastToken.kind === ts.SyntaxKind.CommaToken || lastToken.kind === ts.SyntaxKind.SemicolonToken) {
                                    let result = member.getText().slice(0, -1);
                                    let fix: RuleFix | undefined;
                                    fix = {range: [member.getStart(), member.getEnd()], text: result};
                                    const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                                    this.issueMap.set(defect.fixKey, {defect, fix});
                                }
                            }
                        } else if (isSameLine) {
                            if (this.typeLiteralSingleLineDelimiter === 'semi' && lastToken.kind !== ts.SyntaxKind.SemicolonToken) {
                                let result = this.commaMemberText(lastToken, member);
                                let fix: RuleFix | undefined;
                                fix = {range: [member.getStart(), member.getEnd()], text: result};
                                const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                                this.issueMap.set(defect.fixKey, {defect, fix});
                            }
                            if (this.typeLiteralSingleLineDelimiter === 'comma' && lastToken.kind !== ts.SyntaxKind.CommaToken) {
                                let result = this.semicolonMemberText(lastToken, member);
                                let fix: RuleFix | undefined;
                                fix = {range: [member.getStart(), member.getEnd()], text: result};
                                const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                                this.issueMap.set(defect.fixKey, {defect, fix});
                            }
                        } else if (!isSameLine && isLastMember) {
                            if (this.typeLiteralMultilineRequireLast) {
                                if (this.typeLiteralMultilineDelimiter === 'none' && (lastToken.kind === ts.SyntaxKind.CommaToken || lastToken.kind === ts.SyntaxKind.SemicolonToken)) {
                                    let result = member.getText().slice(0, -1);
                                    let fix: RuleFix | undefined;
                                    fix = {range: [member.getStart(), member.getEnd()], text: result};
                                    const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                                    this.issueMap.set(defect.fixKey, {defect, fix});
                                }
                                if (this.typeLiteralMultilineDelimiter === 'semi' && lastToken.kind !== ts.SyntaxKind.SemicolonToken) {
                                    let result = this.commaMemberText(lastToken, member);
                                    let fix: RuleFix | undefined;
                                    fix = {range: [member.getStart(), member.getEnd()], text: result};
                                    const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                                    this.issueMap.set(defect.fixKey, {defect, fix});
                                }
                                if (this.typeLiteralMultilineDelimiter === 'comma' && lastToken.kind !== ts.SyntaxKind.CommaToken) {
                                    let result = this.semicolonMemberText(lastToken, member);
                                    let fix: RuleFix | undefined;
                                    fix = {range: [member.getStart(), member.getEnd()], text: result};
                                    const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                                    this.issueMap.set(defect.fixKey, {defect, fix});
                                }
                            } else {
                                if (this.typeLiteralMultilineDelimiter === 'none' && (lastToken.kind === ts.SyntaxKind.CommaToken || lastToken.kind === ts.SyntaxKind.SemicolonToken)) {
                                    let result = member.getText().slice(0, -1);
                                    let fix: RuleFix | undefined;
                                    fix = {range: [member.getStart(), member.getEnd()], text: result};
                                    const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                                    this.issueMap.set(defect.fixKey, {defect, fix});
                                }
                            }
                        } else {
                            if (this.typeLiteralMultilineDelimiter === 'none' && (lastToken.kind === ts.SyntaxKind.CommaToken || lastToken.kind === ts.SyntaxKind.SemicolonToken)) {
                                let result = member.getText().slice(0, -1);
                                let fix: RuleFix | undefined;
                                fix = {range: [member.getStart(), member.getEnd()], text: result};
                                const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                                this.issueMap.set(defect.fixKey, {defect, fix});
                            }
                            if (this.typeLiteralMultilineDelimiter === 'semi' && lastToken.kind !== ts.SyntaxKind.SemicolonToken) {
                                let result = this.commaMemberText(lastToken, member);
                                let fix: RuleFix | undefined;
                                fix = {range: [member.getStart(), member.getEnd()], text: result};
                                const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                                this.issueMap.set(defect.fixKey, {defect, fix});
                            }
                            if (this.typeLiteralMultilineDelimiter === 'comma' && lastToken.kind !== ts.SyntaxKind.CommaToken) {
                                let result = this.semicolonMemberText(lastToken, member);
                                let fix: RuleFix | undefined;
                                fix = {range: [member.getStart(), member.getEnd()], text: result};
                                const defect = this.addIssueReport(arkFile, positionInfo.endPosition.line + 1, positionInfo.endPosition.character + 1, positionInfo.endPosition.character + 1, this.metaData.description, fix);
                                this.issueMap.set(defect.fixKey, {defect, fix});
                            }
                        }
                    }
                    this.checkTypeAliasMembers(member, sourceFile, arkFile)
                }
            }
        }
    }

    private commaMemberText(lastToken: ts.Node, member: ts.Node): string {
        let cod: string;
        if (lastToken.kind === ts.SyntaxKind.CommaToken) {
            cod = member.getText().slice(0, -1);
        } else {
            cod = member.getText() + ';';
        }
        return cod;
    }

    private semicolonMemberText(lastToken: ts.Node, member: ts.Node): string {
        let cod: string;
        if (lastToken.kind === ts.SyntaxKind.SemicolonToken) {
            cod = member.getText().slice(0, -1);
        } else {
            cod = member.getText() + ',';
        }
        return cod;
    }

    private getStartLine(node: ts.Node, sourceFile: ts.SourceFile): number {
        const start = node.getStart(sourceFile);
        return sourceFile.getLineAndCharacterOfPosition(start).line + 1;
    }

    private getEndLine(node: ts.Node, sourceFile: ts.SourceFile): number {
        const end = node.getEnd();
        return sourceFile.getLineAndCharacterOfPosition(end).line + 1;
    }

    private getPositionInfo(expression: ts.TypeElement, sourceFile: ts.SourceFileLike) {
        const start = expression.getStart();
        const end = expression.getEnd();
        const startPositionInfo = sourceFile.getLineAndCharacterOfPosition(start);
        const endPositionInfo = sourceFile.getLineAndCharacterOfPosition(end);
        return {
            startPosition: startPositionInfo,
            endPosition: endPositionInfo
        };
    }

    private addIssueReport(arkFile: ArkFile, line: number, startCol: number, endCol: number, message: string, fix?: RuleFix) {
        const severity = this.rule.alert ?? this.metaData.severity;
        const filePath = arkFile.getFilePath();
        const defect = new Defects(line, startCol, endCol, message, severity, this.rule.ruleId,
            filePath, this.metaData.ruleDocPath, true, false, false);
        this.issues.push(new IssueReport(defect, fix));
        RuleListUtil.push(defect);
        return defect;
    }

    private reportSortedIssues(): void {
        if (this.issueMap.size === 0) {
            return;
        }
        const sortedIssues = Array.from(this.issueMap.entries())
            .sort(([keyA], [keyB]) => Utils.sortByLineAndColumn(keyA, keyB));

        this.issues = [];
        sortedIssues.forEach(([_, issue]) => {
            RuleListUtil.push(issue.defect);
            this.issues.push(issue);
        });
    }
}